package cumeo89.chii.client.wikt;

import static cumeo89.chii.client.entry.Constants.*;

import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.NodeList;

final class WikitextGenerator {

	private WikitextGenerator() {
	}

	public static String toWikitext(Document doc) {
		StringBuilder sb = new StringBuilder();
		genEntry(sb, doc.getDocumentElement());
		return sb.toString();
	}

	private static void genEntry(StringBuilder sb, Element root) {
		if ("yes".equalsIgnoreCase(root.getAttribute("info"))) {
			sb.append("{{-info-}}\n\n");
		}

		NodeList langList = root.getElementsByTagName(E_LANG);
		for (int i = 0; i < langList.getLength(); i++) {
			genLang(sb, (Element) langList.item(i));
		}

		NodeList catList = root.getElementsByTagName(E_CATEGORY);
		if (catList.getLength() > 0) {
			sb.append("\n");
			for (int i = 0; i < catList.getLength(); i++) {
				Element cat = (Element) catList.item(i);
				sb.append("\n[[Thể loại:").append(
						cat.getAttribute(A_CATEGORY_NAME)).append("]]");
			}
		}

		NodeList interList = root.getElementsByTagName(E_INTERWIKI);
		String title = root.getAttribute("title");
		if (interList.getLength() > 0) {
			sb.append("\n");
			for (int i = 0; i < interList.getLength(); i++) {
				Element inter = (Element) interList.item(i);
				sb.append("\n[[").append(inter.getAttribute(A_INTERWIKI_LANG))
						.append(":").append(title).append("]]");
			}
		}
	}

	private static void genLang(StringBuilder sb, Element lang) {
		if (lang.getPreviousSibling() != null) {
			sb.append("\n\n");
		}
		sb.append("{{-").append(lang.getAttribute(A_LANG_CODE)).append("-}}");

		genAsTexts(sb, lang, new String[] { "etym", "translit", "pron" });

		genAsLists(sb, lang, new String[] { "nôm", "homo", "paro", "hanviet" });

		NodeList posList = lang.getElementsByTagName(E_POS);
		for (int i = 0; i < posList.getLength(); i++) {
			genPos(sb, (Element) posList.item(i));
		}
	}

	private static void genAsLists(StringBuilder sb, Element parent,
			final String[] lists) {
		for (int i = 0; i < lists.length; i++) {
			NodeList children = parent.getElementsByTagName(lists[i]);
			if (children.getLength() > 0) {
				genTwoColumnList(sb, (Element) children.item(0));
			}
		}
	}

	private static void genAsTexts(StringBuilder sb, Element parent,
			final String[] texts) {
		for (int i = 0; i < texts.length; i++) {
			NodeList children = parent.getElementsByTagName(texts[i]);
			if (children.getLength() > 0) {
				genText(sb, texts[i], children.item(0).getFirstChild()
						.getNodeValue());
			}
		}
	}

	private static void genPos(StringBuilder sb, Element pos) {
		sb.append("\n\n{{-").append(pos.getAttribute("code")).append("-}}");

		if (pos.hasAttribute(A_POS_SPELL)) {
			sb.append("\n").append(pos.getAttribute(A_POS_SPELL));
		}

		NodeList defList = pos.getElementsByTagName(E_DEF);
		for (int i = 0; i < defList.getLength(); i++) {
			genDefinition(sb, (Element) defList.item(i), "#");
		}

		NodeList exprs = pos.getElementsByTagName("expr");
		if (exprs.getLength() > 0) {
			genExpressionList(sb, (Element) exprs.item(0));
		}

		genAsLists(sb, pos, new String[] { "syn", "trans", "redup", "compound",
				"drv", "ant", "rel", });

		genAsTexts(sb, pos, new String[] { "forms", "usage", "ref", });
	}

	private static void genDefinition(StringBuilder sb, Element def,
			String prefix) {
		sb.append("\n").append(prefix);

		NodeList contexts = def.getElementsByTagName(E_CONTEXT);
		if (contexts.getLength() > 0) {
			sb.append(" {{term|");
			for (int i = 0; i < contexts.getLength(); i++) {
				Element context = (Element) contexts.item(i);
				sb.append(context.getAttribute(A_CONTEXT_TEXT));
				if (i < contexts.getLength() - 1) {
					sb.append("; ");
				}
			}
			sb.append("}}");
		}

		sb.append(" ").append(def.getAttribute(A_DEF_CONTENT));

		NodeList exs = def.getElementsByTagName(E_EXAMPLE);
		for (int i = 0; i < exs.getLength(); i++) {
			genExample(sb, (Element) exs.item(i), prefix);
		}
	}

	private static void genExpressionList(StringBuilder sb, Element exprs) {
		sb.append("\n\n{{-").append("expr").append("-}}");
		NodeList items = exprs.getElementsByTagName(E_EXPRESSION);
		for (int i = 0; i < items.getLength(); i++) {
			genExpressionItem(sb, (Element) items.item(i));
		}
	}

	private static void genExpressionItem(StringBuilder sb, Element expr) {
		sb.append("\n* '''").append(
				getElementByTag(sb, expr, "excon").getFirstChild()
						.getNodeValue()).append("''': ");

		NodeList defList = expr.getElementsByTagName(E_DEF);
		if (defList.getLength() == 1
				&& ((Element) defList.item(0)).getElementsByTagName(E_EXAMPLE)
						.getLength() == 0) {
			sb.append("\n").append(
					getElementByTag(sb, (Element) defList.item(0),
							A_DEF_CONTENT).getFirstChild().getNodeValue());
		} else {
			for (int i = 0; i < defList.getLength(); i++) {
				genDefinition(sb, (Element) defList.item(i), "*#");
			}
		}
	}

	private static void genText(StringBuilder sb, String code, String text) {
		if (code != null) {
			sb.append("\n\n{{-").append(code).append("-}}");
		}
		sb.append("\n").append(text);
	}

	private static void genTwoColumnList(StringBuilder sb, Element list) {
		sb.append("\n\n{{-").append(list.getNodeName()).append("-}}");
		NodeList subs = list.getElementsByTagName(E_SUBLIST);
		for (int i = 0; i < subs.getLength(); i++) {
			Element sub = (Element) subs.item(i);

			String title = sub.getAttribute("title");
			if (title.length() > 0) {
				sb.append("\n").append("; ").append(title);
			}

			NodeList items = sub.getElementsByTagName(E_ITEM);
			if (items.getLength() > 3) {
				sb.append("\n{{đầu}}");
				genTwoColumnListItems(sb, items, 0, items.getLength() / 2 + 1);
				sb.append("\n{{giữa}}");
				genTwoColumnListItems(sb, items, items.getLength() / 2 + 1,
						items.getLength());
				sb.append("\n{{cuối}}");
			} else {
				genTwoColumnListItems(sb, items, 0, items.getLength());
			}
		}
	}

	private static void genTwoColumnListItems(StringBuilder sb, NodeList items,
			int from, int to) {
		for (int i = from; i < to; i++) {
			Element item = (Element) items.item(i);
			sb.append("\n* ");
			if (item.hasAttribute("lang")) {
				sb.append("{{").append(item.getAttribute("lang"))
						.append("}}: ");
			}
			sb.append(item.getAttribute("content"));
		}
	}

	private static void genExample(StringBuilder sb, Element ex, String prefix) {
		sb.append("\n").append(prefix).append(": ").append(
				ex.getAttribute("content"));
		String explain = ex.getAttribute(A_EXAMPLE_EXPLAIN);
		if (explain != null && explain.length() > 0) {
			sb.append(" — ").append(explain);
		}
	}

	private static Element getElementByTag(StringBuilder sb, Element parent,
			String tag) {
		NodeList children = parent.getElementsByTagName(tag);
		if (children.getLength() != 1) {
			return null;
		}
		return (Element) children.item(0);
	}

}
